package com.yunao.web.controller;

import com.alibaba.fastjson.JSONObject;
import com.thoughtworks.xstream.XStream;
import com.yunao.commons.enums.ResultEnum;
import com.yunao.commons.utils.*;
import com.yunao.commons.vo.ResultVO;
import com.yunao.entity.ArticleItem;
import com.yunao.entity.User;
import com.yunao.service.ArticleService;
import com.yunao.service.UserService;
import com.yunao.service.report.StringUtil;
import com.yunao.web.config.WxConfig;
import com.yunao.web.mail.QRcodeService;
import com.yunao.web.utils.OutputMessage;
import com.yunao.web.utils.SerializeXmlUtil;
import com.yunao.web.utils.TokenUtil;
import com.yunao.web.utils.WechatUtils;
import com.yunao.web.wechat.object.InputMessage;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/*
* 微信功能
* */
@RestController
@Scope("prototype")
@RequestMapping(value="/favorite/wechat")
@Slf4j
public class PushAction {

    @Autowired
    private UserService userService;

    @Autowired
    private QRcodeService qRcodeService;

    @Autowired
    private ArticleService articleService;

    private String token = "weichat";

    @Value("${wechat.appid}")
    private String appid;

    @Value("${wechat.appsecret}")
    private String appsecret;

    @Value("${wechat.templateId}")
    private String templateId;
    /**
    * get 验证url真实性
    * post 处理微信交互事件
    *
    * @param request 请求
    * @param response 响应
    */
    @RequestMapping(value="/token", method = { RequestMethod.GET, RequestMethod.POST })
    public String checkSignature
            (HttpServletRequest request,
             HttpServletResponse response) {
//        log.info("进入大数据智慧决策公众平台");
        boolean isGet = request.getMethod().toLowerCase().equals("get");
        if (isGet) {
            //验证URL真实性
            log.info("进入get,验证URL真实性");
            return access(request,response);
        } else {
            // 进入POST交互处理
            log.info("进入post,用户交互处理");
            try {
                // 接收消息并返回消息
                acceptMessage(request, response);
            } catch (IOException e) {
                log.error(e.getMessage());
//                e.printStackTrace();
            }
            return null;
        }
    }

    @RequestMapping(value="/weichatList", method = { RequestMethod.GET})
    public List<ArticleItem> weichatList(List<ArticleItem> articles){
        return articles;
    }

    /**
    * @title  模板推送
    * @description 发送预警模板
    * @method post
    * @url /wechat/push
    * request
    * list 文章集合
    *
    */
    @RequestMapping(value="/push",method = RequestMethod.POST)
    public ResultVO<String> push(
//            HttpServletRequest request,
//            String userid,
            @RequestBody(required=false) String body){
        String url = getPostUrl();
        //String openID = "o3XDpjp3c86ICUIg1A15zeHuNLkg";
        JSONObject jsonObject = JSONObject.parseObject(body);
        User user = TokenUtil.getTokenUser(userService);
        String openID = user.getOpenid();

        List<ArticleItem> list = (List<ArticleItem>) jsonObject.get("list");
        JSONObject jsonParam = postParam(openID,templateId,list);

        //发送模板信息
        ResultVO<String> msg = pushMsg(url, jsonParam);
        log.info("当前用户模板推送成功");
        return msg;
    }


    /**
    * showdoc
    * @title  绑定推送
    * @description 扫码并关注，即可绑定微信预警
    * @method post
    * @url /wechat/bind
    * @param msg 可选 String Y(是) 返回二维码链接 N(否) 返回null 默认为Y
    */
    @RequestMapping(value="/bind",method = RequestMethod.POST)
    public ResultVO<String> bindAccount(
            @RequestParam(name = "msg",required = false,defaultValue = "Y")String msg){
        if(msg.equalsIgnoreCase("Y")){
            User user = TokenUtil.getTokenUser(userService);
            String accessToken = WechatUtils.accessToken.getAccess_token();
            return qRcodeService.qRcode(accessToken,user.getUserId()+"");
        }else {
            return ResultVOUtil.error(ResultEnum.WECHAT_QRCODE_ERROR);
        }
    }

    @RequestMapping("/existUserWeichat")
    public ResultVO<Boolean> existUserWeichat(){
        User user = TokenUtil.getTokenUser(userService);
        return ResultVOUtil.success(StringUtils.isEmpty(user.getOpenid()));
    }
    /*
    * 模板推送url
    * */
    private String getPostUrl(){
        String accessToken = WechatUtils.accessToken.getAccess_token();
        return "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+accessToken;
    }
    /*
    * 验证url真实性
    * */
    private String access(
            HttpServletRequest request,
            HttpServletResponse response
    ){
        String signature = request.getParameter("signature");// 微信加密签名
        String timestamp = request.getParameter("timestamp");// 时间戳
        String nonce = request.getParameter("nonce");// 随机数
        String echostr = request.getParameter("echostr");// 随机字符串

        // 1.将token、timestamp、nonce三个参数进行字典序排序
        String[] arr = new String[] { token, timestamp, nonce };
        Arrays.sort(arr);

        // 2. 将三个参数字符串拼接成一个字符串进行sha1加密
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        MessageDigest md = null;
        String tmpStr = null;
        try {
            md = MessageDigest.getInstance("SHA-1");
            // 将三个参数字符串拼接成一个字符串进行sha1加密
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        content = null;
        // 3.将sha1加密后的字符串可与signature对比，标识该请求来源于微信
        String toUp = signature.toUpperCase();
        boolean boo = tmpStr != null ? tmpStr.equals(toUp) : false;
        if(boo){
            try {
                log.info("成功返回 echostr：{}" , echostr);
                return echostr;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        log.info("认证失败");
        return null;
    }
    /*
    * post交互事件
    * */
    private void acceptMessage(
            HttpServletRequest request,
            HttpServletResponse response
    ) throws IOException {
        // 处理接收消息
        ServletInputStream in = request.getInputStream();
        // 将POST流转换为XStream对象
        XStream xs = SerializeXmlUtil.createXstream();
        xs.processAnnotations(InputMessage.class);
        xs.processAnnotations(OutputMessage.class);
        // 将指定节点下的xml节点数据映射为对象
        xs.alias("xml", InputMessage.class);
        // 将流转换为字符串
        StringBuilder xmlMsg = new StringBuilder();
        byte[] b = new byte[4096];
        for (int n; (n = in.read(b)) != -1;) {
            xmlMsg.append(new String(b, 0, n, "UTF-8"));
        }
        // 将xml内容转换为InputMessage对象
        InputMessage inputMsg = (InputMessage) xs.fromXML(xmlMsg.toString());
        System.out.println(inputMsg.toString());
        // 取得消息类型
        String msgType = inputMsg.getMsgType();
        // 事件类型
        String event = inputMsg.getEvent();
        String eventKey = inputMsg.getEventKey();
        // 根据消息类型获取对应的消息内容
        if (msgType.equals(MsgType.Event.toString())) {
            if(event.equalsIgnoreCase("SCAN")){
                // 扫码事件
//                System.out.println("开发者微信号：" + inputMsg.getToUserName());
//                System.out.println("发送方帐号：" + inputMsg.getFromUserName());
//                System.out.println("消息创建时间：" + inputMsg.getCreateTime() + new Date(createTime * 1000l));
                String userid = eventKey;
                userService.updateOpenidByUserid(inputMsg.getFromUserName(),userid);

                User user = userService.findOne(Integer.parseInt(userid));
                log.info("用户【{}】 已绑定模板推送功能",user.getUsername());
            }
            if(event.equalsIgnoreCase("subscribe")){
                String userid = eventKey.split("_")[1];
                userService.updateOpenidByUserid(inputMsg.getFromUserName(),userid);

                User user = userService.findOne(Integer.parseInt(userid));
                log.info("用户【{}】 已绑定模板推送功能",user.getUsername());
            }
        }
    }

    //JSON格式参数
    private JSONObject postParam(String openID, String templateId, List list){
        JSONObject jsonParam = new JSONObject();
        jsonParam.put("touser",openID);//收信息人
        jsonParam.put("template_id",templateId);//模板id

        //模板信息
        JSONObject data = new JSONObject();
        JSONObject title = new JSONObject();//标题
        title.put("value","云奥大数据预警信息");
        title.put("color","#173177");
        JSONObject keyword1 = new JSONObject();//内容
        keyword1.put("value","您关注的预警有新的信息，共监测到"+list.size()+"篇文章");
        keyword1.put("color","#173177");
        JSONObject keyword2 = new JSONObject();//时间
        String time =  simpleDateFormat.format(new Date(System.currentTimeMillis()));
        keyword2.put("value",time);
        keyword2.put("color","#173177");
        JSONObject remak = new JSONObject();//点击查看详情
        remak.put("value","可点击详情查看更多内容");
        remak.put("color","#173177");

        data.put("first",title);
        data.put("keyword1",keyword1);
        data.put("keyword2",keyword2);
        data.put("remak",remak);

        jsonParam.put("data",data);
        jsonParam.put("url","www.baidu.com");
        return jsonParam;
    }
    //post请求发送模板信息
    private ResultVO<String> pushMsg(String url,JSONObject jsonParam){

        HttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost(url);
        post.setHeader("Content-Type", "application/json");
        post.addHeader("Authorization", "Basic YWRtaW46");
        String result = "";
        try {
            StringEntity s = new StringEntity(jsonParam.toString(), "utf-8");
            s.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
            post.setEntity(s);

            // 发送请求
            org.apache.http.HttpResponse httpResponse = client.execute(post);

            // 获取响应输入流
            InputStream inStream = httpResponse.getEntity().getContent();
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    inStream, "utf-8"));
            StringBuilder strber = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null)
                strber.append(line + "\n");
            inStream.close();

            result = strber.toString();
            log.info("推送模板信息结果 : {}",result);

            if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                return ResultVOUtil.success("推送成功");
            } else {
                return ResultVOUtil.error(ResultEnum.WECHAT_PUSH_ERROR);
            }
        } catch (IOException e) {
            log.error(e.getMessage());
        }
        return ResultVOUtil.error(ResultEnum.WECHAT_PUSH_ERROR);
    }

    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");

    private static String byteToStr(byte[] byteArray) {
        StringBuilder strDigest = new StringBuilder();
        for (int i = 0; i < byteArray.length; i++) {
            strDigest.append(byteToHexStr(byteArray[i]));
        }
        return strDigest.toString();
    }

    private static String byteToHexStr(byte mByte) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
                'B', 'C', 'D', 'E', 'F' };
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];
        String s = new String(tempArr);
        return s;
    }

}
